#include "storagemanager.h"
#include <dirent.h>
#include <limits.h>
#include "redismanager.h"

//判断是否为目录  [AUTO-TRANSLATED:639e15fa]
//Determine if it is a directory
bool File::is_dir(const std::string &path) {
    auto dir = opendir(path.data());
    if (!dir) {
        return false;
    }
    closedir(dir);
    return true;
}

//判断是否为常规文件  [AUTO-TRANSLATED:59e6b610]
//Determine if it is a regular file
bool File::fileExist(const std::string &path) {
    auto fp = fopen(path.data(), "rb");
    if (!fp) {
        return false;
    }
    fclose(fp);
    return true;
}

//判断是否是特殊目录  [AUTO-TRANSLATED:cda5ed9f]
//Determine if it is a special directory
bool File::is_special_dir(const std::string &path) {
    return path == "." || path == "..";
}

bool File::saveFile(const string &data, const std::string &path) {
    FILE *fp = fopen(path.data(), "wb");
    if (!fp) {
        return false;
    }
    fwrite(data.data(), data.size(), 1, fp);
    fclose(fp);
    return true;
}

string File::parentDir(const std::string &path) {
    auto parent_dir = path;
    if (parent_dir.back() == '/') {
        parent_dir.pop_back();
    }
    auto pos = parent_dir.rfind('/');
    if (pos != string::npos) {
        parent_dir = parent_dir.substr(0, pos + 1);
    }
    return parent_dir;
}

void File::scanDir(const std::string &path_in, const function<bool(const string &path, bool is_dir)> &cb,
                   bool enter_subdirectory, bool show_hidden_file) {
    string path = path_in;
    if (path.back() == '/') {
        path.pop_back();
    }

    DIR *pDir;
    dirent *pDirent;
    if ((pDir = opendir(path.data())) == nullptr) {
        //文件夹无效  [AUTO-TRANSLATED:ee3339ea]
        //Invalid folder
        return;
    }
    while ((pDirent = readdir(pDir)) != nullptr) {
        if (is_special_dir(pDirent->d_name)) {
            continue;
        }
        if (!show_hidden_file && pDirent->d_name[0] == '.') {
            //隐藏的文件  [AUTO-TRANSLATED:3b2eb642]
            //Hidden file
            continue;
        }
        string strAbsolutePath = path + "/" + pDirent->d_name;
        bool isDir = is_dir(strAbsolutePath);
        if (!cb(strAbsolutePath, isDir)) {
            //不再继续扫描  [AUTO-TRANSLATED:991bdb3f]
            //Stop scanning
            break;
        }

        if (isDir && enter_subdirectory) {
            //如果是文件夹并且扫描子文件夹，那么递归扫描  [AUTO-TRANSLATED:36773722]
            //If it's a folder and scanning subfolders, then recursively scan
            scanDir(strAbsolutePath, cb, enter_subdirectory);
        }
    }
    closedir(pDir);
}


StorageManager::StorageManager()
{

}

StorageManager::~StorageManager()
{

}

StorageManager *StorageManager::getInstacne()
{
    static StorageManager manager;
    return &manager;
}

void StorageManager::initStorageParam(const std::string &recordDir, int maxCache, int maxDays, int delMode, int delCount, int delSize)
{
    //固定为record
    m_storageRootDir = recordDir + "/record";
    m_maxCache = maxCache;
    m_maxDay = maxDays;
    m_autoDeleteMode = delMode;
    m_autoDeleteSize = delSize;
    m_autoDeleteCount = delCount;

    log_printf(LOG_LEV, "StorageManager %d %d %s %d %d %d", maxCache, maxDays, recordDir.c_str(), delMode, delCount, delSize);

    //获取所有文件
    collectAllRecordFile();
}

void StorageManager::collectAllRecordFile()
{
    string record_path = mk_util_get_exe_dir("record");

    //这是筛选日期，获取文件夹列表
    File::scanDir(record_path, [&](const string &path, bool isDir)
    {
        auto pos = path.rfind('/');
        if (pos != string::npos)
        {
            if (!isDir)
            {
                STU_FILEINFO info;
                info.duration = 0;
                info.fileName = path;
                info.path = path;
                experimental::filesystem::path p(path);
                experimental::filesystem::file_time_type lasttime = last_write_time(p);
                auto duration = lasttime.time_since_epoch();
                auto filelast = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
                // 将时间差转换为毫秒
                info.createTime = filelast.count();
                info.size= file_size(p);

                m_mapRecordFiles.insert(std::make_pair(info.createTime, info));
            }
        }
        else if (isDir)
        {
            //只收集文件，对文件夹不感兴趣
        }

        return true;
    },
    true);
}

uint64_t StorageManager::getFileTotalSize()
{
    uint M = 1 * 1024 * 1024;
    uint64_t cache = 0;
    for (auto info : m_mapRecordFiles)
    {
        cache += info.second.size;
    }
    return cache / M;
}

uint64_t StorageManager::getFileMaxDuration()
{
    uint64_t duration = 0;
    if(!m_mapRecordFiles.empty())
    {
        duration = m_mapRecordFiles.begin()->second.createTime;
    }

    for (auto info : m_mapRecordFiles)
    {
        if (duration < info.second.createTime)
            duration = info.second.createTime;
    }

    //返回秒
    return duration / 1000;
}

void StorageManager::addOneFile(const STU_FILEINFO &info)
{
    checkAndAutoDelete();
    m_mapRecordFiles.insert(std::make_pair(info.createTime, info));

    //发送redis通知
    Json::Value root;
    root["payload_name"] = info.cameraName;
    root["payload_type"] = info.cameraType;
    root["media_type"] = info.mediaType;
    root["start_time"] = info.startTime;
    root["end_time"] = info.stoptime;
    root["duration"] = info.duration;
    root["file_size"] = info.size;
    root["file_path"] = info.path;
    string json = root.toStyledString();

    RedisManager::getInstance()->addFile(json);
}

void StorageManager::delOneFile(const string &filePath)
{
    //删除实际文件
    int result = std::remove(filePath.c_str());
    if(result)
    {
        log_printf(LOG_LEV, "delOneFile error! %s", filePath.c_str());
        return;
    }

    //发送redis通知
    RedisManager::getInstance()->delFile(filePath);
}

void StorageManager::checkAndAutoDelete()
{
    std::vector<std::string> vecDeletePath;

    uint64_t curSize = getFileTotalSize();
    int duration = getFileMaxDuration();
    int daySecs = 24 * 60 * 60;
    int curDays = duration / daySecs;
    if ((curSize > m_maxCache) || curDays > m_maxDay)
    {
        //超过最大缓存或者时长 delMode 0按个数 1按大小
        log_printf(LOG_LEV, "checkAndAutoDelete DeleteFile");
        int delCount = 0;
        int delSize = 0;

        for(auto it = m_mapRecordFiles.begin(); it != m_mapRecordFiles.end(); it++)
        {
            if (m_autoDeleteMode == 0)
            {
                delCount++;
                if(delCount > m_autoDeleteCount)
                {
                    break;
                }
            }
            else if (m_autoDeleteMode == 1)
            {
                delSize += it->second.size;
                if (delSize > m_autoDeleteSize)
                {
                    break;
                }
            }

            vecDeletePath.push_back(it->second.path);
            m_mapRecordFiles.erase(it);
        }
    }

    //删除文件
    for(uint i=0; i<vecDeletePath.size(); i++)
    {
        std::string path = vecDeletePath.at(i);
        delOneFile(path);
    }
}
